package com.smalltao.core.aop;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Throwables;
import com.smalltao.core.base.dao.SysLogRepository;
import com.smalltao.core.base.entity.SysLog;
import com.smalltao.core.utils.BeanUtils;
import com.smalltao.core.utils.ToolsUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;

/**
 * @author smallTao.liu
 * @version V1.0
 * @description AOP API请求记录
 * @date 2018/11/14 15:00
 */
@Aspect
@Component
public class SmalltaoLogAspect {

    private Logger logger = LoggerFactory.getLogger(SmalltaoLogAspect.class);

    @Value("${logging.dbUrlLog}")
    private boolean dbUrlLog;

    @Value("${logging.dbExLog}")
    private boolean dbExLog;

    @Autowired
    private SysLogRepository sysLogRepository;

    @Pointcut("execution(public * com.smalltao..controller..*.*(..))")
    public void webLog() {

    }

    @After("webLog()")
    public void doAfter(JoinPoint joinPoint) {
        handleLog(joinPoint, null);
    }

    @AfterThrowing(value = "webLog()", throwing = "ex")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable ex) {
        handleLog(joinPoint, ex);
    }

    private void handleLog(JoinPoint joinPoint, Throwable ex) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        String logMethod = targetName + "." + methodName + "()";

        Object[] arguments = joinPoint.getArgs();
        StringBuilder params = new StringBuilder();
        if (arguments != null && arguments.length > 0) {
            for (int i = 0; i < arguments.length; i++) {
                // 如果参数为HttpServletRequest 、HttpServletResponse 不加入params
                if (arguments[i] == null || arguments[i] instanceof HttpServletRequest || arguments[i] instanceof HttpServletResponse) {
                    continue;
                }
                params.append(JSON.toJSONString(arguments[i])).append(";");
            }
        }

        SysLog sysLog = new SysLog();
        sysLog.setLogType("url请求");
        // 获取登录用户
        Subject subject = SecurityUtils.getSubject();
        if (ToolsUtil.isNotNull(subject.getPrincipal())) {
            Map<String, Object> map = BeanUtils.beanToMap(subject.getPrincipal());
            sysLog.setCreateBy(String.valueOf(map.get("userName")));
        }
        sysLog.setCreateTime(new Date());
        sysLog.setDetails(request.getRequestURI());
        sysLog.setMethod(logMethod);
        sysLog.setParams(params.toString());
        sysLog.setReqIp(request.getRemoteAddr());

        // 获取自定义注解日志参数
        try {
            Class<?> targetClass = Class.forName(targetName);
            Method[] methods = targetClass.getMethods();
            for (Method method : methods) {
                if (method.getName().equals(methodName)) {
                    Class[] clazzs = method.getParameterTypes();
                    if (clazzs != null && clazzs.length == arguments.length && method.getAnnotation(SmalltaoLog.class) != null) {
                        sysLog.setOperationType(method.getAnnotation(SmalltaoLog.class).operationType());
                        sysLog.setOperationName(method.getAnnotation(SmalltaoLog.class).operationName());
                        break;
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        if (ToolsUtil.isNotNull(ex)) {
            sysLog.setLogType("ex异常");
            sysLog.setExCode(ex.getClass().getName());
            sysLog.setExMsg(ex.getMessage());
            sysLog.setExDetail(Throwables.getStackTraceAsString(ex));
            // 将日志记录到日志表
            logger.error(sysLog.getLogType() + "：" + sysLog.getExMsg());
            if (dbExLog) {
                sysLogRepository.save(sysLog);
            }
        } else {
            // 将日志记录到日志表
            if (dbUrlLog) {
                logger.info(sysLog.getLogType() + "：" + JSON.toJSON(sysLog));
                sysLogRepository.save(sysLog);
            }
        }

    }
}
